﻿using System;
using System.Collections.Specialized;
using System.Text.RegularExpressions;
using RuTracker.Interface;
using RuTracker.Interface.Login;
using RuTrackerLib.ServiceAttibutes;

namespace RuTrackerLib.Tracker
{
    [PerCallService]
    public class RuTrackerAccessor : ITrackerAccessor
    {
        private const string TrackerName = "rutracker.org";

        private readonly IResponseLexer _resultsResponseLexer;
        private readonly IWebClient _webclient;

        public RuTrackerAccessor(IWebClient webClient
            , IResponseLexer responseLexer
            , ITrackerInfoRepository trackerInfoRepository)
        {
            TrackerInfo = trackerInfoRepository.GetTrackerInfo(TrackerName);
            _webclient = webClient;
            _resultsResponseLexer = responseLexer;
        }
      
        /// <summary>
        /// Returns true in case if user is already signed in
        /// </summary>
        public bool IsSignedIn()
        {
            var html =_webclient.DownloadString(TrackerInfo.DefaultUrl);
            return _resultsResponseLexer.GetResults(html).Succeeded;
        }
        
        /// <summary>
        /// signs user into ruTracker. returns true if user was successfully signed into
        /// </summary>
        public LoginResults SignIn(string user, string password)
        {
            try
            {
                string html = _webclient.UploadValues(TrackerInfo.LoginPageUrl, new NameValueCollection
                                                        {
                                                            {"login_username", user},
                                                            {"login_password", password},
                                                            {"login", "%C2%F5%EE%E4"}
                                                        });
                return _resultsResponseLexer.GetResults(html);
            }
            catch (Exception ex)
            {
                throw new RuTrackerAccessException("Error during accessing to RuTracker", ex);
            }
        }

        /// <summary>
        /// Signs user with using capture interface
        /// </summary>
        public LoginResults SignInWithCapture(string user, string password, string captchaCode, string captchaCodeValue, string captchaSid)
        {
            string html = _webclient.UploadValues(TrackerInfo.LoginPageUrl, new NameValueCollection
                                                        {
                                                            {"redirect", "index.php"},
                                                            {"login_username", user},
                                                            {"login_password", password},
                                                            {"cap_sid", captchaSid},
                                                            {captchaCode, captchaCodeValue},
                                                            {"login", "%C2%F5%EE%E4"}
                                                        });
            return _resultsResponseLexer.GetResults(html);
        }

        public LoginResults Search(string query)
        {
            string html = _webclient.UploadValues(TrackerInfo.SearchUrl, new NameValueCollection
                                                                 {
                                                                     {"max", "1"},
                                                                     {"to", "1"},
                                                                     {"nm", query}
                                                                 });

            return _resultsResponseLexer.GetResults(html);
        }

        public LoginResults GoToAddress(string url)
        {
            string html = _webclient.DownloadString(url);

            return _resultsResponseLexer.GetResults(html);
        }

        /// <summary>
        /// Signs user out. returns true if user was signed out successfully
        /// </summary>
        public bool SignOut()
        {
            try
            {
                string html = _webclient.UploadValues(TrackerInfo.LoginPageUrl, new NameValueCollection { { "logout", "1" } });
                return !_resultsResponseLexer.GetResults(html).Succeeded;
            }
            catch (Exception ex)
            {
                throw new RuTrackerAccessException("Error during accessing to RuTracker", ex);
            }
        }

        /// <summary>
        /// Gets stream to download torrent file from Url topic
        /// </summary>
        public byte[] GetTorrentFromTopic(Uri uri)
        {
            string downloadedPage = _webclient.DownloadString(uri.AbsoluteUri);
            if (!_resultsResponseLexer.ContainsTorrent(downloadedPage))
                throw new RuTrackerAccessException(string.Format("Topic: '{0}' doesn't contain torrent for downloading", uri.AbsoluteUri));
            
            string torrentLink = GetTorrentLink(downloadedPage);

            if (string.IsNullOrWhiteSpace(torrentLink))
                throw new RuTrackerAccessException(string.Format("Cannot resolve torrent for downloading from topic '{0}'", uri.AbsoluteUri));

            try
            {
                return _webclient.UploadBinaryValues(torrentLink, new NameValueCollection());
            }
            catch (Exception ex)
            {
                throw new RuTrackerAccessException("Error during accessing to RuTracker", ex);
            }
        }

        public TrackerInformation TrackerInfo { get; private set; }

        private string GetTorrentLink(string pageHtml)
        {
            Regex regex = new Regex("<a\\s+href=\"(?<link>.*?)\".*>Скачать .torrent</a>", RegexOptions.Compiled | RegexOptions.Multiline);
            return regex.Match(pageHtml).Groups["link"].Value;
        }
    }
}
